package jf.states.graph;

import java.util.Map;
import java.util.List;
import java.util.HashMap;

import jf.closure.F3;
import jf.collections.Tuple3;
import jf.collections.CollectionF;
import static jf.collections.CollectionF.asIList;

/**
 *
 * 
 *
 * @author ivanalx
 * @date 06.05.2009 15:52:31
 */
public class GraphDescription<S, A, T> {

	public static <S,A,T> GraphDescription<S,A,T> createGraphDescription(Tuple3<S, A, ? extends F3<S, A, T, S>>... transitions) {
		return new GraphDescription<S,A,T>(transitions);
	}

	private final Map<S, Map<A, F3<S, A, T,S>>> validTransitionsForState;
	private final Map<A, Map<S, F3<S, A, T,S>>> validTransitionsForAction;

	public GraphDescription(Tuple3<S, A, ? extends F3<S, A, T, S>>... transitions) {
		List<Tuple3<S, A, ? extends F3<S, A, T, S>>> description = CollectionF.asIList(transitions);
		validTransitionsForState = new HashMap<S, Map<A, F3<S,A,T,S>>>();
		validTransitionsForAction = new HashMap<A, Map<S, F3<S,A,T,S>>>();
		for (Tuple3<S, A, ? extends F3<S, A, T, S>> d : description) {
			Map<A, F3<S, A, T, S>> vs = validTransitionsForState.get(d._1);
			if (vs == null) {
				vs = new HashMap<A, F3<S,A,T,S>>();
				validTransitionsForState.put(d._1, vs);
			}
			vs.put(d._2, d._3);

			Map<S, F3<S, A, T, S>> va = validTransitionsForAction.get(d._2);
			if (va == null) {
				va = new HashMap<S, F3<S,A,T,S>>();
				validTransitionsForAction.put(d._2, va);
			}
			va.put(d._1, d._3);
		}
	}



	public List<A> getValidActionsForState(S s) {
		Map<A, F3<S, A, T, S>> map = validTransitionsForState.get(s);
		return map == null ? CollectionF.<A>emptyImmutableList() : asIList(map.keySet());
	}

	public List<S> getValidStatesForAction(A a) {
		Map<S, F3<S, A, T, S>> map = validTransitionsForAction.get(a);
		return map == null ? CollectionF.<S>emptyImmutableList() : asIList(map.keySet());
	}

	public F3<S, A, T, S> getFunction(S state, A action) {
		Map<A, F3<S, A, T, S>> map = validTransitionsForState.get(state);
		if (map != null) {
			return map.get(action);
		} else {
			return null;
		}
	}
}
